<template>
	<div class="excel-container">
		<!-- 导出功能 -->
		<el-card class="box-card">
			<template #header>
				<div class="card-header">
					<span>数据导出</span>
					<div>
						<el-button
							color="#000"
							type="primary"
							@click="exportExcel"
							:loading="exporting"
							:disabled="tableData.length === 0"
						>
							{{ exporting ? "正在导出..." : "导出为 Excel" }}
						</el-button>
						<el-button type="success" @click="addNewRow" color="#007acc">
							新增一行
						</el-button>
					</div>
				</div>
			</template>
			<div>
				<p>点击按钮，将下面的表格数据导出为 Excel 文件。</p>
			</div>
		</el-card>

		<!-- 导入功能 -->
		<el-card class="box-card">
			<template #header>
				<div class="card-header">
					<span>数据导入</span>
				</div>
			</template>
			<p>拖拽 Excel 文件到下方区域或点击上传，数据将更新至下方表格。</p>
			<el-upload
				class="upload-dragger"
				drag
				action=""
				:show-file-list="false"
				:auto-upload="false"
				:on-change="handleFileChange"
				accept=".xlsx, .xls"
			>
				<el-icon class="el-icon--upload"><upload-filled /></el-icon>
				<div class="el-upload__text">
					将文件拖到此处，或 <em>点击上传</em>
				</div>
				<template #tip>
					<div class="el-upload__tip">
						仅支持 .xls 或 .xlsx 格式的文件
					</div>
				</template>
			</el-upload>
		</el-card>

		<!-- 数据展示 -->
		<el-card class="box-card">
			<template #header>
				<div class="card-header">
					<span>数据预览</span>
					<span v-if="tableData.length > 0" class="total-count"
						>共 {{ tableData.length }} 条数据</span
					>
				</div>
			</template>
			<div
				v-loading="importing"
				element-loading-text="正在拼命解析数据..."
			>
				<!-- 
        虚拟滚动功能的表格组件：ElTableV2
        缺点：需要固定宽高，就是为了简化计算才需要固定宽高
        如果动态行高时，复杂度会呈指数级增长
        具体思路会在readme中详细说明
        -->
				<!-- <el-table-v2
          v-if="tableData.length > 0"
          :columns="tableColumns"
          :data="tableData"
          :width="1000" 
          :height="400" 
          fixed
        /> -->
				<!-- 也可以用分页做优化  -->
				<el-table
					ref="tableRef"
					:data="paginatedData"
					border
					style="width: 100%"
					row-key="id"
					@row-dragstart="handleDragStart"
					@row-dragover="handleDragOver"
					@row-drop="handleDrop"
				>
					<template v-if="tableHeaders.length > 0">
						<el-table-column
							v-for="header in tableHeaders"
							:key="header"
							:prop="header"
							:label="headerMapping[header] || header"
							sortable
						>
							<template #default="{ row, column, $index }">
								<div
									@dblclick="
										handleCellDblClick(
											row,
											column.property,
											$index +
												(currentPage - 1) * pageSize
										)
									"
									class="cell-content"
								>
									<el-input
										v-if="
											editingCell?.rowIndex ===
												$index +
													(currentPage - 1) *
														pageSize &&
											editingCell?.key === column.property
										"
										v-model="row[column.property]"
										@blur="handleEditBlur"
										@keydown.enter.prevent="handleEditBlur"
										v-focus
									/>
									<span v-else>{{
										row[column.property]
									}}</span>
								</div>
							</template>
						</el-table-column>

						<el-table-column
							label="操作"
							width="100"
							align="center"
							fixed="right"
						>
							<template #default="{ $index }">
								<el-button
									type="danger"
									size="small"
									@click="
										deleteRow(
											$index +
												(currentPage - 1) * pageSize
										)
									"
									>删除</el-button
								>
							</template>
						</el-table-column>
					</template>
					<template #empty>
						<el-empty
							description="暂无数据，请先从上方导入一个 Excel 文件"
						/>
					</template>
				</el-table>
				<el-pagination
					v-model:current-page="currentPage"
					v-model:page-size="pageSize"
					:page-sizes="[20, 50, 100, 200]"
					layout="total, sizes, prev, pager, next, jumper"
					:total="tableData.length"
				/>
			</div>
		</el-card>
	</div>
</template>

<script setup lang="ts">
import { ref, computed, Directive } from "vue";
import * as XLSX from "xlsx";
import { Column, ElMessage, ElMessageBox, UploadFile } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";

// --- 类型定义 ---
type TableRow = Record<string, any>;
interface EditingCell {
	rowIndex: number;
	key: string;
}

const PLACEHOLDER_TEXT = "请填写数据";

const currentPage = ref(1);
const pageSize = ref(50);
const paginatedData = computed(() => {
	const start = (currentPage.value - 1) * pageSize.value;
	const end = start + pageSize.value;
	return tableData.value.slice(start, end);
});

const editingCell = ref<EditingCell | null>(null);
const draggingRowIndex = ref<number | null>(null);

// 虚拟滚动功能的表格组件：ElTableV2
const tableColumns = computed<Column[]>(() => {
	if (tableData.value.length === 0) return [];
	const keys = Object.keys(tableData.value[0]);
	return keys.map(key => ({
		key: key,
		dataKey: key,
		title: headerMapping[key] || key,
		width: 150, // 可以为每列指定宽度
		sortable: true,
	}));
});

// --- 状态 State ---
const tableData = ref<TableRow[]>([
	{ id: 1, name: "张三", age: 25, city: "北京" },
	{ id: 2, name: "李四", age: 30, city: "上海" },
	{ id: 3, name: "王五", age: 22, city: "广州" },
]);
const importing = ref(false);
const exporting = ref(false);

// --- 表头映射 (可根据需要扩展) ---
const headerMapping: Record<string, string> = {
	id: "ID",
	name: "姓名",
	age: "年龄",
	city: "城市",
	// ... 其他可能的映射
};

// --- 计算属性 Computed ---
const tableHeaders = computed<string[]>(() => {
	if (tableData.value.length === 0) return [];
	// 使用第一行数据的键作为表头
	return Object.keys(tableData.value[0]);
});

// --- 方法 Methods ---

// 处理单元格双击，进入编辑状态
const handleCellDblClick = (row: TableRow, key: string, rowIndex: number) => {
	// 如果是占位符，则清空以方便用户输入
	if (row[key] === PLACEHOLDER_TEXT) {
		row[key] = "";
	}
	editingCell.value = { rowIndex, key };
};

// 输入框失焦，退出编辑状态
const handleEditBlur = () => {
	if (!editingCell.value) return;

	const { rowIndex, key } = editingCell.value;
	const row = tableData.value[rowIndex];

	// 如果编辑后内容为空，则恢复为占位符
	if (row && (row[key] === null || String(row[key]).trim() === "")) {
		row[key] = PLACEHOLDER_TEXT;
	}

	editingCell.value = null;
	ElMessage.success("修改成功！");
};

// 新增一行
const addNewRow = () => {
	if (tableHeaders.value.length === 0) {
		ElMessage.warning("请先导入或创建带有表头的数据！");
		return;
	}
	const newRow: TableRow = {};
	tableHeaders.value.forEach(key => {
		if (key === "id") {
			newRow[key] = Date.now(); // 确保新行有唯一的 key
		} else {
			newRow[key] = PLACEHOLDER_TEXT;
		}
	});
	tableData.value.unshift(newRow); // unshift 在顶部添加，体验更好
	ElMessage.success("新增成功，请填写数据！");
};

const deleteRow = (index: number) => {
	ElMessageBox.confirm("确定要删除这一行数据吗？", "警告", {
		confirmButtonText: "确定",
		cancelButtonText: "取消",
		type: "warning",
	})
		.then(() => {
			tableData.value.splice(index, 1);
			ElMessage.success("删除成功！");
		})
		.catch(() => {
			ElMessage.info("已取消删除");
		});
};

/**
 * 开始拖拽
 */
const handleDragStart = (row: TableRow) => {
	const index = tableData.value.findIndex(item => item.id === row.id);
	if (index !== -1) {
		draggingRowIndex.value = index;
	}
};

/**
 * 拖拽经过
 */
const handleDragOver = (e: DragEvent) => {
	e.preventDefault(); // 必须阻止默认事件，否则 drop 事件不会触发
};

/**
 * 放置
 */
const handleDrop = (e: DragEvent, dropRow: TableRow) => {
	e.preventDefault();
	if (draggingRowIndex.value === null) return;

	const dropIndex = tableData.value.findIndex(item => item.id === dropRow.id);
	if (dropIndex === -1) return;

	// 执行移动操作
	const [draggedItem] = tableData.value.splice(draggingRowIndex.value, 1);
	tableData.value.splice(dropIndex, 0, draggedItem);

	ElMessage.success("排序成功！");
	draggingRowIndex.value = null;
};

/**
 * 导出 Excel
 */
const exportExcel = () => {
	if (tableData.value.length === 0) {
		ElMessage.warning("没有数据可以导出！");
		return;
	}
	exporting.value = true;

	// 准备导出的数据（将 key 转换为中文表头）
	const dataToExport = tableData.value.map(row => {
		const newRow: Record<string, any> = {};
		for (const key in row) {
			const newKey = headerMapping[key] || key;
			newRow[newKey] = row[key];
		}
		return newRow;
	});

	setTimeout(() => {
		try {
			const workbook = XLSX.utils.book_new();
			const worksheet = XLSX.utils.json_to_sheet(dataToExport);
			XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
			XLSX.writeFile(
				workbook,
				`导出数据_${new Date().toLocaleString()}.xlsx`
			);
			ElMessage.success("导出成功！");
		} catch (error) {
			console.error("导出失败:", error);
			ElMessage.error("导出失败，请查看控制台日志。");
		} finally {
			exporting.value = false;
		}
	}, 500);

	// 备选 优化方案 开启另一个线程
	// 其他方案： 流式生成与下载（Streaming） 时间分片（Time Slicing）/ 任务分块 服务器端生成 readme中详细说明
	// const worker = new Worker('/workers/export.worker.js');
	// // 监听来自 Worker 的消息
	// worker.onmessage = (e) => {
	//   const { success, buffer, error } = e.data;
	//   if (success) {
	//     // Worker 成功返回了文件数据，现在在主线程触发下载
	//     const blob = new Blob([buffer], { type: 'application/octet-stream' });
	//     const link = document.createElement('a');
	//     link.href = URL.createObjectURL(blob);
	//     link.download = `worker导出数据_${new Date().toLocaleString()}.xlsx`;
	//     document.body.appendChild(link);
	//     link.click();
	//     document.body.removeChild(link);
	//     URL.revokeObjectURL(link.href); // 释放内存
	//     ElMessage.success('文件已开始下载！');
	//   } else {
	//     console.error('Worker 导出失败:', error);
	//     ElMessage.error(`导出失败: ${error}`);
	//   }

	//   // 结束任务
	//   exporting.value = false;
	//   worker.terminate(); // 关闭 worker，释放资源
	// };

	// worker.onerror = (e) => {
	//   console.error('Worker 发生错误:', e);
	//   ElMessage.error('导出进程发生未知错误。');
	//   exporting.value = false;
	//   worker.terminate();
	// };

	// // 向 Worker 发送需要处理的数据
	// try {
	//   worker.postMessage({
	//     data: toRaw(tableData.value),
	//     headerMapping: toRaw(headerMapping)  // 把表头映射也传过去
	//   });
	// } catch (error) {
	//   console.error('Worker 发生错误:', error);
	//   ElMessage.error('导出进程发生未知错误。');
	// }
};

/**
 * 处理文件选择与解析
 * @param {UploadFile} uploadFile - ElUpload 组件传递的文件对象
 */
const handleFileChange = (uploadFile: UploadFile) => {
	if (!uploadFile.raw) return;

	const file = uploadFile.raw;
	const fileType = file.name.substring(file.name.lastIndexOf(".") + 1);
	const validTypes = ["xlsx", "xls"];

	if (!validTypes.includes(fileType)) {
		ElMessage.error("文件格式不正确，请上传 .xls 或 .xlsx 文件！");
		return;
	}

	importing.value = true;

	// 使用 FileReader 读取文件
	const reader = new FileReader();
	reader.onload = (e: ProgressEvent<FileReader>) => {
		try {
			const data = e.target?.result;
			const workbook = XLSX.read(data, {
				type: "array",
				cellDates: true,
			});
			const sheetName = workbook.SheetNames[0];
			const worksheet = workbook.Sheets[sheetName];
			console.log("worksheet:", worksheet);
			// --- 关键修复点 ---
			// 使用 `defval: ''` 来确保空单元格被转换为空字符串，而不是被忽略。
			// 这有助于 `sheet_to_json` 更准确地处理数据矩阵，避免因空值导致行数识别错误。
			// `blankrows: false` 也是一个好习惯，可以忽略纯粹的空行。
			const jsonData = XLSX.utils.sheet_to_json(worksheet, {
				defval: "", // 为空单元格设置默认值
				blankrows: false, // 跳过空行
			});
			console.log("jsonData:", jsonData);

			// 导入成功后，将原始英文 key 的数据赋给 tableData
			tableData.value = jsonData as TableRow[];
			ElMessage.success(`成功导入 ${jsonData.length} 条数据！`);
		} catch (error) {
			console.error("文件解析失败:", error);
			ElMessage.error("文件解析失败，请确保文件格式或内容正确。");
		} finally {
			importing.value = false;
		}
	};

	reader.onerror = () => {
		ElMessage.error("文件读取失败！");
		importing.value = false;
	};

	reader.readAsArrayBuffer(file);
};
</script>

<style scoped>
.excel-container {
	padding: 20px;
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.box-card {
	width: 100%;
}

.card-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.total-count {
	font-size: 14px;
	color: #909399;
}

.upload-dragger {
	margin-top: 10px;
}

p {
	font-size: 14px;
	color: #606266;
	margin-top: 0;
}
</style>
